介绍
装饰(Decorator)模式:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。
装饰模式也称为包装模式,结构型设计模式之一,其使用一种对客户端透明的方式来动态地扩展对象地功能,同时它也是继承关系的一种替代方案之一。
优点
- 采用装饰模式扩展对象的功能比采用继承方式更加灵活。
- 可以设计出多个不同的具体装饰类,创造出多个不同行为的组合。
缺点
装饰模式增加了许多子类,如果过度使用会使程序变得很复杂。
使用场景
需要透明且动态地扩展类的功能。
结构与实现
通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征,耦合度高,并且随着扩展功能的增多,子类会很膨胀。如果使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能,这就是装饰模式的目标。下面来分析其基本结构和实现方法。
模式包含以下主要角色。
- Component(抽象组件):接口或者抽象类,被装饰的最原始的对象。具体组件与抽象装饰角色的父类。
- ConcreteComponent(具体组件):实现抽象组件的接口。
- Decorator(抽象装饰角色):一般是抽象类,抽象组件的子类,同时持有一个被装饰者的引用,用来调用被装饰者的方法;同时可以给被装饰者增加新的职责。
- ConcreteDecorator(具体装饰类):抽象装饰角色的具体实现。
其结构图如下图所示。
代码如下:
程序运行结果如下:
示例
人总是要穿衣服,我们将人定义为一个抽象类,将其穿衣服的行为定义为一个抽象方法,代码如下:
PersonCloth 用来装饰 Person:
下面两个是继承 PersonCloth 的实际装饰类:
测试代码:
ANDROID 源码中的实现
Context 类在 Android 中被称为“上帝对象”,它本质是一个抽象类,其在我们装饰者模式里相当于抽象组件,而在其内部定义了大量的抽象方法,比如我们经常会用到的 startActivity 方法。
真正的实现是在 ContextImpl 中完成的,ContextImpl 继承自 Context 抽象类,并实现了 Context 中的抽象方法。
这里 ContextImpl 就相当于组件具体实现类,那么谁来承担装饰者的身份呢?
Activity 从类层次上来说本质是一个 Context。Activity 并非直接继承于 Context,而是继承于 ContextThemeWrapper。
而这个 ContextThemeWrapper 又是继承于 ContextWrapper。
最终这个 ContextWrapper 才继承于 Context。
为什么类层次会这么复杂呢?其实这里就是一个典型的装饰模式,ContextWrapper 就是我们要找的装饰者,在 ContextWrapper 中有一个 Context 的引用。
ContextWrapper 类的 startActivity 方法如下:
可以看出它调用了 ContextImpl 中对应的方法。
装饰模式应用的套路都是很相似的,对于具体方法的包装扩展则由 ContextWrapper 的具体子类完成,比如我们的 Activity、Service 和 Application。